home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 3
/
Cream of the Crop 3.iso
/
comm
/
wnos5src.zip
/
NRCMD.C
< prev
next >
Wrap
Text File
|
1993-08-09
|
26KB
|
1,164 lines
/* net/rom user command processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#include "global.h"
#include "config.h"
#ifdef NETROM
#include "mbuf.h"
#include "ax25.h"
#include "mailbox.h"
#include "netrom.h"
#include "nr4.h"
#include "timer.h"
#include "iface.h"
#include "cmdparse.h"
#include "session.h"
#include "socket.h"
#include "commands.h"
#include "files.h"
/* Nodes message broadcast address: "NODES" in shifted ASCII */
/* defined in ax25rout.c: Ax25multi[1] */
char Nr4user[AXALEN];
char *Nr4states[] = {
"Disconnected",
"Conn Pending",
"Connected",
"Disc Pending",
"Listen (S)"
} ;
char *Nr4reasons[] = {
"Normal",
"By Peer",
"Timeout",
"Reset",
"Refused"
} ;
int Nr_save = 1; /* NET/ROM Route Save on by default */
int donrsave __ARGS((void));
static char *Nodelist = NULLCHAR;
static struct timer Nodetimer ; /* timer for nodes broadcasts */
static struct timer Obsotimer ; /* timer for aging routes */
static char badcall[] = "Bad destination callsign\n";
static char badnb[] = "Bad neighbor callsign\n";
int
doroutedump(int argc,char *argv[],void *p)
{
#define MAX_LES_ROUTES 150
struct nrroute_tab *rp ;
char buf[18], temp[18], les_routes[MAX_LES_ROUTES][18], *cp;
int count = 0, column = 1, in, out, i;
for (i = 0 ; i < NRNUMCHAINS ; i++) {
for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
if(count > MAX_LES_ROUTES - 1)
break;
strcpy(buf,rp->alias) ;
/* remove trailing spaces */
if ((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if (cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
pax25(cp,rp->call) ;
if(argc == 9) {
if (buf[0] != '#') { /* NREX bke 920809 */
count++;
strcpy(les_routes[count],buf);
}
continue;
}
if(argc == 10) { /* NREX bke 920809 */
count++;
strcpy(les_routes[count],buf);
continue;
} /* bke */
if(strstr(buf,"TCP") != NULL
|| strstr(buf,"NOS") != NULL
|| strstr(buf,"IP") != NULL) {
count++;
strcpy(les_routes[count],buf);
}
}
if(count > MAX_LES_ROUTES - 1) {
tprintf("\nOnly %d routes displayed\n",MAX_LES_ROUTES);
break;
}
}
for (out = 1; out < count; out++)
for (in = out+1; in < count+1; in++)
if (strcmp(les_routes[out],les_routes[in]) > 0 ) {
strcpy(temp, les_routes[in]);
strcpy(les_routes[in], les_routes[out]);
strcpy(les_routes[out], temp);
}
for(i = 1; i <= count; i++) {
tprintf("%-16s ", les_routes[i]);
if( column++ == 4) {
tputs("\n");
column = 1;
}
}
if(column != 1)
tputs("\n");
return 0 ;
}
/* print detailed information on an individual route */
int
dorouteinfo(int argc,char *argv[],void *p)
{
struct nrroute_tab *rp ;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
char dest[AXALEN], neighbor[AXBUF], alias[AXBUF], *cp;
if (setcall(dest,argv[1]) == -1) {
tputs (badcall);
return -1 ;
}
if(putalias(alias,argv[1],0) != -1
&& (cp = find_nralias(alias)) != NULLCHAR)
memcpy(dest,cp,AXALEN);
if((rp = find_nrroute(dest)) == NULLNRRTAB) {
if(argc < 9)
tprintf("*** no route to %s\n",pax25(neighbor,dest)) ;
return -1 ;
}
for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
np = bp->via ;
if(tprintf("%1s %3d %3d %-8s %s\n",
(bp->flags & NRB_PERMANENT ? "P" :
bp->flags & NRB_RECORDED ? "R" : " "),
bp->quality,bp->obsocnt,
Nrifaces[np->iface].iface->name,
pax25(neighbor,np->call)) == EOF)
break;
}
return 0 ;
}
/* convert a null-terminated alias name to a blank-filled, upcased */
/* version. Return -1 on failure. */
int
putalias(char *to,char *from,int complain)
{
int len, i ;
if ((len = strlen(from)) > ALEN) {
if (complain)
tputs ("Max six chars\n") ;
return -1 ;
}
for (i = 0 ; i < ALEN ; i++) {
if (i < len) {
if (islower(*from))
*to++ = toupper(*from++) ;
else
*to++ = *from++ ;
}
else
*to++ = ' ' ;
}
*to = '\0' ;
return 0 ;
}
/* find a netrom interface, gives a msg if 'msg' is set != 0 */
static int near
nrif_lookup(char *call,int msg)
{
int i;
for (i = 0 ; i < Nr_numiface ; i++)
if (!strcmp(Nrifaces[i].iface->name,call))
break ;
if (i == Nr_numiface) {
if(msg)
tprintf(Badif,call);
return -1 ;
}
return i;
}
/* Add a route */
static int
dorouteadd(int argc,char *argv[],void *p)
{
char alias[AXALEN], dest[AXALEN], neighbor[AXALEN];
unsigned quality ;
int i ;
/* format alias (putalias prints error message if necessary) */
if (putalias(alias,argv[1],1) == -1)
return -1 ;
/* format destination callsign */
if (setcall(dest,argv[2]) == -1) {
tputs(badcall);
return -1 ;
}
if((i = nrif_lookup(argv[3],1)) == -1)
return -1;
/* format neighbor address string */
if (setcall(neighbor,argv[5]) == -1) {
tputs(badcall);
return -1;
}
#ifdef XXX
/* Change from 871225 -- no digis in net/rom table */
if (argc > 6)
tputs("digis given: set route with ax25 route cmd\n");
#endif
/* get and check quality value */
quality = (unsigned)min(atoi(argv[4]),255);
return nr_routeadd(alias,dest,i,quality,neighbor,1,0) ;
}
/* drop a route */
static int
doroutedrop(int argc,char *argv[],void *p)
{
char dest[AXALEN], neighbor[AXALEN] ;
int i ;
/* format destination and neighbor callsigns */
if (setcall(dest,argv[1]) == -1) {
tputs(badcall);
return -1 ;
}
if (setcall(neighbor,argv[2]) == -1) {
tputs(badnb);
return -1 ;
}
if((i = nrif_lookup(argv[3],1)) == -1)
return -1;
return nr_routedrop(dest,neighbor,i) ;
}
/* make an interface available to net/rom */
static int
dointerface(int argc,char *argv[],void *p)
{
int i ;
struct iface *ifp ;
if (Nr_iface == NULLIF)
nr_attach(0,0,p);
if (Nr_numiface >= NRNUMIFACE) {
tprintf("Max %d NET/ROM ifaces\n",NRNUMIFACE);
return 1 ;
}
if((ifp = if_lookup(argv[1])) == NULLIF){
tprintf(Badif,argv[1]);
return 1;
}
for (i = 0 ; i < Nr_numiface ; i++)
if (Nrifaces[i].iface == ifp) {
tprintf("Iface %s already registered\n",argv[1]) ;
return 1 ;
}
Nrifaces[Nr_numiface].iface = ifp ;
/* NREX bke 920716 */
if(argc == 5) {
if(setcall(Nrifaces[Nr_numiface].call,argv[4]) == -1)
return 1;
} else {
memcpy(Nrifaces[Nr_numiface].call,Mycall,AXALEN);
}
if (putalias(Nrifaces[Nr_numiface].alias,argv[2],1) == -1)
return 1 ;
Nrifaces[Nr_numiface].quality = (unsigned)min(atoi(argv[3]),255);
Nr_numiface++ ; /* accept this interface */
return 0 ;
}
static void
donodetick(void)
{
if(Nr_numiface) {
int i;
stop_timer(&Nodetimer);
for (i = 0 ; i < Nr_numiface ; i++)
nr_bcnodes(i,Ax25multi[1]) ;
if(strchr(Nodelist,'*') != NULLCHAR) {
char *cp1 = strxdup(Nodelist);
char *cp = strtok(cp1,"*");
while((cp = strtok(NULL,"*")) != NULLCHAR)
nr_bcnodes(Nr_numiface - 1,cp);
xfree(cp1);
}
}
/* restart timer */
start_timer(&Nodetimer);
}
/* Broadcast nodes list on named interface. */
static int
dobcnodes(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
int j;
char call[AXALEN];
int i = nrif_lookup(argv[1],(argc < 3) ? 1 : 0);
if(argc < 3) {
if(i == -1)
return -1;
nr_bcnodes(i,Ax25multi[1]);
return 0;
}
if(i == -1) {
argc++;
argv--;
}
if(Nodelist) {
xfree(Nodelist);
}
Nodelist = cxallocw(argc + 1,AXBUF);
for(j = 1; j < argc; j++) {
if(setcall(call,argv[j]) == -1)
continue;
strcat(Nodelist,call);
strcat(Nodelist,"*");
}
donodetick();
return 0;
}
/* Set outbound node broadcast interval */
static int
donodetimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Nodetimer %lu/%lu s\n",
read_timer(&Nodetimer)/1000L,
dur_timer(&Nodetimer)/1000L);
return 0;
}
/* in case it's already running */
stop_timer(&Nodetimer) ;
/* what to call on timeout */
Nodetimer.func = (void (*) __ARGS((void *))) donodetick;
Nodetimer.arg = NULLCHAR; /* dummy value */
set_timer(&Nodetimer,atol(argv[1]) * 1000L); /* set timer duration */
start_timer(&Nodetimer); /* and fire it up */
return 0;
}
/* Go through the routing table, reducing the obsolescence count of
* non-permanent routes, and purging them if the count reaches 0
*/
static void
doobsotick()
{
struct nrnbr_tab *np ;
struct nrroute_tab *rp, *rpnext ;
struct nr_bind *bp, *bpnext ;
int i ;
stop_timer(&Obsotimer);
for (i = 0 ; i < NRNUMCHAINS ; i++) {
for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
rpnext = rp->next ; /* save in case we free this route */
for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
bpnext = bp->next ; /* in case we free this binding */
if (bp->flags & NRB_PERMANENT) /* don't age these */
continue ;
if (--bp->obsocnt == 0) { /* time's up! */
if (bp->next != NULLNRBIND)
bp->next->prev = bp->prev ;
if (bp->prev != NULLNRBIND)
bp->prev->next = bp->next ;
else
rp->routes = bp->next ;
rp->num_routes-- ; /* one less binding */
np = bp->via ; /* find the neighbor */
xfree(bp) ; /* now we can free the bind */
/* Check to see if we can free the neighbor */
if (--np->refcnt == 0) {
if (np->next != NULLNTAB)
np->next->prev = np->prev ;
if (np->prev != NULLNTAB)
np->prev->next = np->next ;
else {
Nrnbr_tab[nrhash(np->call)] = np->next ;
}
xfree(np) ; /* free the storage */
}
}
}
if (rp->num_routes == 0) { /* did we free them all? */
if (rp->next != NULLNRRTAB)
rp->next->prev = rp->prev ;
if (rp->prev != NULLNRRTAB)
rp->prev->next = rp->next ;
else
Nrroute_tab[i] = rp->next ;
xfree(rp) ;
}
}
}
start_timer(&Obsotimer) ;
}
/* Set timer for aging routes */
static int
doobsotimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Obsotimer %lu/%lu s\n",
read_timer(&Obsotimer)/1000L,
dur_timer(&Obsotimer)/1000L);
return 0;
}
/* just in case it's already running */
stop_timer(&Obsotimer) ;
/* what to call on timeout */
Obsotimer.func = (void (*) __ARGS((void *))) doobsotick;
Obsotimer.arg = NULLCHAR; /* dummy value */
set_timer(&Obsotimer,atol(argv[1]) * 1000L); /* set timer duration */
start_timer(&Obsotimer); /* and fire it up */
return 0;
}
/* display a list of <callsign,interface> pairs from the filter
* list.
*/
static int
donfdump(void)
{
int i, column = 1 ;
struct nrnf_tab *fp ;
char buf[16] ;
for (i = 0 ; i < NRNUMCHAINS ; i++)
for (fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
pax25(buf,fp->neighbor) ;
tprintf("%-7s %-8s %-3d ",
buf,Nrifaces[fp->iface].iface->name, fp->quality) ;
if (column++ == 3) {
if(tputs("\n") == EOF)
return 0;
column = 1 ;
}
}
if (column != 1)
tputs("\n");
return 0 ;
}
/* add an entry to the filter table */
static int
donfadd(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char neighbor[AXALEN] ;
int i ;
unsigned qual = atoi(argv[3]);
/* format callsign */
if (setcall(neighbor,argv[1]) == -1) {
tputs(badnb);
return -1 ;
}
if((i = nrif_lookup(argv[2],1)) == -1)
return -1;
if(argc < 4)
qual = Nrifaces[i].quality;
return nr_nfadd(neighbor,i,qual) ;
}
/* drop an entry from the filter table */
static int
donfdrop(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char neighbor[AXALEN] ;
int i ;
/* format neighbor callsign */
if (setcall(neighbor,argv[1]) == -1) {
tputs(badnb);
return -1 ;
}
if((i = nrif_lookup(argv[2],1)) == -1)
return -1;
return nr_nfdrop(neighbor,i) ;
}
/* nodefilter mode subcommand */
static int
donfmode(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if (argc < 2) {
tputs("Filter mode: ");
switch (Nr_nfmode) {
case NRNF_NOFILTER:
tputs("none\n") ;
break ;
case NRNF_ACCEPT:
tputs("accept\n") ;
break ;
case NRNF_REJECT:
tputs("reject\n") ;
break ;
default:
tputs("unknown\n") ;
}
} else {
switch (tolower(argv[1][0])) {
case 'n':
Nr_nfmode = NRNF_NOFILTER ;
break ;
case 'a':
Nr_nfmode = NRNF_ACCEPT ;
break ;
case 'r':
Nr_nfmode = NRNF_REJECT ;
break ;
default:
tputs("Usage: mode <accept|reject|none>\n");
return -1 ;
}
}
return 0;
}
/* nodefilter command multiplexer */
static int
donodefilter(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct cmds Nfcmds[] = {
"add", donfadd, 0, 3,
"netrom nodefilter add <neighbor> <iface> [<quality>]",
"drop", donfdrop, 0, 3,
"netrom nodefilter drop <neighbor> <iface>",
"mode", donfmode, 0, 0, NULLCHAR,
NULLCHAR,
} ;
if (argc < 2) {
donfdump() ;
return 0 ;
}
return subcmd(Nfcmds,argc,argv,p) ;
}
/* netrom network packet time-to-live initializer */
static int
donrttl(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr_ttl,"TTL",argc,argv);
}
/* verbose route broadcast */
static int
donrverbose(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setbool(&Nr_verbose,"Verbose",argc,argv);
}
/* allow automatic derating of netrom routes on link failure */
static int
donrderate(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_derate;
return setbool(&Nr_derate,"Derate",argc,argv);
}
/* promiscuous acceptance of broadcasts */
static int
donrpromisc(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_promisc;
return setbool(&Nr_promisc,"Promiscuous",argc,argv);
}
/* Initiate a NET/ROM transport connection */
static int
donrconnect(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char *np ;
struct sockaddr_nr lsocket, fsocket;
char alias[AXBUF];
struct session *sp;
/* Get a session descriptor */
if ((sp = newsession(argv[1],NRSESSION,SPLIT | SWAP)) == NULLSESSION) {
tputs(Nosess);
return 1;
}
if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
tputs(Nosocket);
goto quit;
}
lsocket.nr_family = AF_NETROM;
/* Set up our local username, bind would use Mycall instead */
memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
/* Putting anything else than Mycall here will not work */
memcpy(lsocket.nr_addr.node,Mycall,AXALEN);
bind(sp->s,(char *)&lsocket,SOCKSIZE);
/* See if the requested destination could be an alias, and */
/* find and use it if it is. Otherwise assume it is an ax.25 */
/* address. */
if (putalias(alias,argv[1],0) != -1 &&
(np = find_nralias(alias)) != NULLCHAR) {
memcpy(fsocket.nr_addr.user,np,AXALEN) ;
memcpy(fsocket.nr_addr.node,np,AXALEN) ;
} else { /* parse ax25 callsign */
/* Only the user callsign of the remote station is never used by */
/* NET/ROM, but it is needed for the psocket() call. */
setcall(fsocket.nr_addr.user,argv[1]);
setcall(fsocket.nr_addr.node,argv[1]);
}
fsocket.nr_family = AF_NETROM;
pax25(alias,fsocket.nr_addr.node);
if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
return 0;
quit:
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
/* Reset a net/rom connection abruptly */
static int
donrreset(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
if(!nr4valcb(cb)){
tputs(Notval);
return 1;
}
reset_nr4(cb);
return 0;
}
/* Allows a manual forced close on a net/rom connection */
static int
donrclose(int argc,char *argv[],void *p)
{
struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
if(!nr4valcb(cb)) {
tputs(Notval);
return 1;
}
disc_nr4(cb);
return 0;
}
/* Force retransmission on a net/rom connection */
static int
donrkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
if(!nr4valcb(cb)){
tputs(Notval);
return 1;
}
return kick_nr4(cb);
}
/* netrom transport ACK delay timer */
static int
donracktime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setintrc(&Nr4acktime,"Ack delay",argc,argv,1,60);
}
/* netrom transport choke timeout */
static int
donrchoketime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setintrc(&Nr4choketime,"Choke timeout",argc,argv,10,3600);
}
/* netrom transport initial round trip time */
static int
donrirtt(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setintrc(&Nr4irtt,"IRTT",argc,argv,5,360);
}
/* netrom transport receive queue length limit. This is the */
/* threshhold at which we will CHOKE the sender. */
static int
donrqlimit(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setintrc(&Nr4qlimit,"Queue limit",argc,argv,1,4096);
}
/* Display or change our NET/ROM username */
static int
donruser(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[AXBUF];
if(argc < 2){
tprintf("%s\n",pax25(buf,Nr4user));
return 0;
}
if(setcall(Nr4user,argv[1]) == -1)
return -1;
Nr4user[ALEN] |= E;
return 0;
}
/* netrom transport maximum window. This is the largest send and */
/* receive window we may negotiate */
static int
donrwindow(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setintrc(&Nr4window,"Window",argc,argv,1,NR4MAXWIN);
}
/* netrom transport maximum retries. This is used in connect and */
/* disconnect attempts; I haven't decided what to do about actual */
/* data retries yet. */
static int
donrretries(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4retries,"Retry limit",argc,argv);
}
/* Display the status of NET/ROM connections */
static int
donrstatus(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
int i ;
struct nr4cb *cb ;
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
if (argc < 2) {
tputs("&NRCB Snd-W Snd-Q Rcv-Q LUser RUser @Node State\n");
for (i = 0 ; i < NR4MAXCIRC ; i++) {
if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
continue ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
if(tprintf("%lx %3d %5d %5d %9s %9s %-9s %s\n",
ptol(cb), cb->nbuffered, len_q(cb->txq),
len_p(cb->rxq), luser, ruser, node,
Nr4states[cb->state]) == EOF)
break;
}
return 0 ;
}
cb = (struct nr4cb *)shtop(argv[1]) ;
if (!nr4valcb(cb)) {
tputs(Notval);
return 1 ;
}
donrdump(cb) ;
return 0 ;
}
/* Dump one control block */
void
donrdump(cb)
struct nr4cb *cb ;
{
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
unsigned seq ;
struct nr4txbuf *b ;
struct timer *t ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
luser, cb->mynum, cb->myid, ruser, node,
cb->yournum, cb->yourid, Nr4states[cb->state]) ;
tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\nTACK: ",
cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
if (run_timer(&cb->tack))
tprintf("%lu", read_timer(&cb->tack)) ;
else
tputs("-") ;
tprintf("/%lu ms TChoke: ", dur_timer(&cb->tack)) ;
if (run_timer(&cb->tchoke))
tprintf("%lu", read_timer(&cb->tchoke)) ;
else
tputs("-") ;
tprintf("/%lu ms TCD: ", dur_timer(&cb->tchoke)) ;
if (run_timer(&cb->tcd))
tprintf("%lu", read_timer(&cb->tcd)) ;
else
tputs("-") ;
tprintf("/%lu ms\nTries: %u Inactive: %ld/%ld sec",
dur_timer(&cb->tcd),
cb->cdtries,
read_timer(&cb->inactivity)/1000L,
dur_timer(&cb->inactivity)/1000L);
if(cb->blevel)
tprintf(" Backoff Level %u",cb->blevel);
tprintf("\nSRTT %ld ms Mean dev %ld ms\n", cb->srtt, cb->mdev) ;
/* If we are connected and the send window is open, display */
/* the status of all the buffers and their timers */
if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
tputs("TxBuffers: Seq Size Tries Timer\n") ;
for (seq = cb->ackxpected ;
nr4between(cb->ackxpected, seq, cb->nextosend) ;
seq = (seq + 1) & NR4SEQMASK) {
b = &cb->txbufs[seq % cb->window] ;
t = &b->tretry ;
if(tprintf(" %3u %3d %5d %lu/%lu\n",
seq, len_p(b->data), b->retries + 1, read_timer(t), dur_timer(t))
== EOF)
break;
}
}
}
static int
dominquality(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
return setintrc(&(int16)Nr_autofloor,"MinQual",argc,argv,1,255);
}
/* Switch on/off saving of netrom routes to disk */
static int
doroutesave(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setbool(&Nr_save,"NET/ROM Route Save",argc,argv);
}
static char * near
getarg(char *line)
{
char *arg;
int c;
static char *p;
if (line) p = line;
while (isspace(uchar(*p))) p++;
arg = p;
while (*p && !isspace(uchar(*p))) {
c = (uchar(*p));
*p++ = c;
}
if (*p) *p++ = '\0';
return arg;
}
/*
* Load saved NET/ROM routes - called at startup
*/
int
donrload(void)
{
FILE *fn;
int quality, i, j;
char buff[LINELEN], *alias = 0, *dest, *type, *iface, *neighbor;
char ax25_alias[AXALEN], ax25_dest[AXALEN], ax25_nbor[AXALEN], *ptr;
if((fn = Fopen(Nrroutefile,READ_TEXT,0,1)) == NULLFILE)
return 1;
while(fgets(buff,LINELEN,fn) != NULL) {
alias = dest = type = iface = neighbor = 0;
quality = 0;
if((ptr = strchr(buff,':')) == 0){
*alias = '\0';
dest = getarg(buff);
} else {
*ptr = ' ';
alias = getarg(buff);
dest = getarg(0);
}
type = getarg(0);
quality = atoi(getarg(0));
getarg(0);
iface = getarg(0);
neighbor = getarg(0);
/* find interface */
for(i = 0 ; i < Nr_numiface ; i++)
if(!strcmp(Nrifaces[i].iface->name,iface))
break ;
if(i == Nr_numiface) {
tprintf(Badif,iface);
continue;
}
/* Convert to NET/ROM routing table formats */
putalias(ax25_alias, alias, 0);
setcall(ax25_dest, dest);
setcall(ax25_nbor, neighbor);
/* get and check quality value */
if(quality > 255)
quality = 255;
if (*type == 'P')
j = 0;
else
j = 1;
nr_routeadd(ax25_alias,ax25_dest,i,quality,ax25_nbor,!j,j);
}
Fclose(fn);
return 0;
}
/*
* Save NET/ROM routes in file for reading when we start up again.
* This function is called at each tick of the netrom obsotimer.
*
*/
int
donrsave(void)
{
struct nrroute_tab *rp ;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
char neighbor[AXBUF], buf[18], *cp;
int i;
FILE *fn;
if((fn = Fopen(Nrroutefile,WRITE_TEXT,0,1)) == NULLFILE)
return 1;
for(i = 0 ; i < NRNUMCHAINS ; i++){
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
sprintf(buf,"%.*s",AXALEN,rp->alias) ;
/* remove trailing spaces */
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
pax25(cp,rp->call) ;
fprintf(fn,"%-16s ",buf) ;
np = bp->via ;
fprintf(fn,"%1s %3d %3d %-8s %s\n",
(bp->flags & NRB_PERMANENT ? "P" :
bp->flags & NRB_RECORDED ? "R" : "X"),
bp->quality,bp->obsocnt,
Nrifaces[np->iface].iface->name,
pax25(neighbor,np->call));
}
}
}
Fclose(fn);
return 0;
}
/* Route command multiplexer */
static int
donrroute(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct cmds Routecmds[] = {
"add", dorouteadd, 0, 6,
"netrom route add <alias> <destination> <iface> <quality> <neighbor>",
"drop", doroutedrop, 0, 4,
"netrom route drop <destination> <neighbor> <iface>",
"info", dorouteinfo, 0, 2,
"netrom route info <destination>",
"save", doroutesave, 0, 0,
"netrom route save [<0|1>]",
NULLCHAR,
} ;
if (argc < 2) {
return doroutedump(9,0,p);
}
if(argc == 3 && stricmp(argv[2],"tcp") == 0) {
return doroutedump(0,0,p);
}
return subcmd(Routecmds,argc,argv,p) ;
}
/* Command multiplexer */
int
donetrom(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct cmds Nrcmds[] = {
"acktime", donracktime, 0, 0, NULLCHAR,
"bcnodes", dobcnodes, 0, 2, "netrom bcnodes <iface> [<call>]",
"connect", donrconnect, 1024, 2, "netrom connect <node>",
"choketime", donrchoketime, 0, 0, NULLCHAR,
"close", donrclose, 0, 2, "netrom close <nrcb>",
"derate", donrderate, 0, 0, NULLCHAR,
"interface", dointerface, 0, 4,
"netrom interface <iface> <alias> <quality> [<call>]",
"irtt", donrirtt, 0, 0, NULLCHAR,
"kick", donrkick, 0, 2, "netrom kick <nrcb>",
"minquality", dominquality, 0, 0, NULLCHAR,
"nodefilter", donodefilter, 0, 0, NULLCHAR,
"nodetimer", donodetimer, 0, 0, NULLCHAR,
"obsotimer", doobsotimer, 0, 0, NULLCHAR,
"promiscuous", donrpromisc, 0, 0, NULLCHAR,
"qlimit", donrqlimit, 0, 0, NULLCHAR,
"reset", donrreset, 0, 2, "netrom reset <nrcb>",
"retries", donrretries, 0, 0, NULLCHAR,
"route", donrroute, 0, 0, NULLCHAR,
"status", donrstatus, 0, 0, NULLCHAR,
"ttl", donrttl, 0, 0, NULLCHAR,
"user", donruser, 0, 0, NULLCHAR,
"verbose", donrverbose, 0, 0, NULLCHAR,
"window", donrwindow, 0, 0, NULLCHAR,
NULLCHAR,
} ;
return subcmd(Nrcmds,argc,argv,p) ;
}
#endif /* NETROM */